package com.alex.formates.epub;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Vector;

import nl.siegmann.epublib.domain.Book;
import nl.siegmann.epublib.domain.TOCReference;
import nl.siegmann.epublib.epub.EpubReader;
import android.util.Log;

import com.alex.books.BaseBook;
import com.alex.books.Chapter;
import com.alex.formates.ReaderPlugin;
import com.alex.util.HtmlConverter;

/**
 * 解析epub格式
 * 
 * @author Alex.Lu
 * 
 */
public class EPUBPlugin extends ReaderPlugin {
	
	private int mBufBegin;
	private int mBufEnd;
	
	@Override
	public Object generatedCatalog(BaseBook book, File file, int mode) {
		// TODO Auto-generated method stub
		try {
			InputStream epubInputStream = new BufferedInputStream(new FileInputStream(file));
			Book mBook = (new EpubReader()).readEpub(epubInputStream);
			book.mBookName = mBook.getTitle();
			logTableOfContents(book,mBook.getTableOfContents().getTocReferences(), 0);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private int number = 0;
	/**
	 * Recursively Log the Table of Contents
	 * 
	 * @param tocReferences
	 * @param depth
	 */
	private void logTableOfContents(BaseBook book,List<TOCReference> tocReferences, int depth) {
		book.mChapters = new Vector<Chapter>();
		if (tocReferences == null) {
			return;
		}
		for (int j=0;j<tocReferences.size();j++) {
			TOCReference tocReference =tocReferences.get(j);
			StringBuilder tocString = new StringBuilder();
			for (int i = 0; i < depth; i++) {
				tocString.append("\t");
			}
			tocString.append(tocReference.getTitle());
			String str = null;
			try {
				str = new String(tocReference.getResource().getData());
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			String context = HtmlConverter.html2text(str);
			Chapter chapter = new Chapter();
			chapter.mBookId = book.mBookId;
			chapter.mChapterName = tocReference.getTitle();
			chapter.mPosBegin = 0;
			chapter.mPosEnd = context.length();
			chapter.mLength = chapter.mPosEnd;
			number += chapter.mLength;
			chapter.mContent = HtmlConverter.html2text(str);
			Log.i("epublib:", chapter.mChapterName);
			//Log.i("content:", HtmlConverter.html2text(str));
			book.mChapters.add(chapter);
			// logTableOfContents(tocReference.getChildren(), depth + 1);
			
			book.mChapters.get(j).mContent = HtmlConverter.html2text(str);
			Log.i("epublib:", book.mChapters.get(j).mChapterName);
			Log.i("content:", HtmlConverter.html2text(str));
		}
		
		book.mWordNumber = ""+number;
		mBaseBook = book;
	}
	
	/**
	 * Recursively Log the Table of Contents
	 * 
	 * @param tocReferences
	 * @param depth
	 */
	private void logTableOfContents2(BaseBook book,List<TOCReference> tocReferences, int depth) {
		if (tocReferences == null) {
			return;
		}
		for (int j=0;j<tocReferences.size();j++) {
			TOCReference tocReference =tocReferences.get(j);
			StringBuilder tocString = new StringBuilder();
			for (int i = 0; i < depth; i++) {
				tocString.append("\t");
			}
			tocString.append(tocReference.getTitle());
			String str = null;
			try {
				str = new String(tocReference.getResource().getData());
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			book.mChapters.get(j).mContent = HtmlConverter.html2text(str);
			Log.i("epublib:", book.mChapters.get(j).mChapterName);
			Log.i("content:", HtmlConverter.html2text(str));
		}
		mBaseBook = book;
	}
	
	@Override
	public Object decode(BaseBook Book, File file) {
		// TODO Auto-generated method stub
		try {
			InputStream epubInputStream = new BufferedInputStream(new FileInputStream(file));
			Book mBook = (new EpubReader()).readEpub(epubInputStream);
			Book.mBookName = mBook.getTitle();
			logTableOfContents2(Book,mBook.getTableOfContents().getTocReferences(), 0);
			Book.mReaderingInfo.mCurChapter = Book.mChapters.get(Book.mReaderingInfo.mIndex); 
			mBufBegin = mBufEnd  = (int) Book.mReaderingInfo.mMarkPos;
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public boolean isFirstChapter() {
		// TODO Auto-generated method stub
		if(mBaseBook.mReaderingInfo.mIndex <= 0){
			return true;
		}
		return false;
	}


	@Override
	public boolean isLastChapter() {
		// TODO Auto-generated method stub
		if(mBaseBook.mReaderingInfo.mIndex >= mBaseBook.mChapters.size()-1){
			return true;
		}
		return false;
	}

	@Override
	public boolean isFirstPage() {
		// TODO Auto-generated method stub
		if(mBaseBook.mReaderingInfo.mIndex <= 0
				&&	mBufBegin <= mBaseBook.mChapters.get(0).mPosBegin){
				return true;
			}
		return false;
	}
	
	@Override
	public boolean isLastPage() {
		// TODO Auto-generated method stub
		if(mBaseBook.mReaderingInfo.mIndex >= mBaseBook.mChapters.size()-1
			&&	mBufEnd >= mBaseBook.mReaderingInfo.mCurChapter.mPosEnd){
			return true;
		}
		return false;
	}

	@Override
	public String nextChapter() {
		if(mBaseBook.mReaderingInfo.mIndex+1<mBaseBook.mChapters.size()){
			mBaseBook.mReaderingInfo.mIndex++;
			mBaseBook.mReaderingInfo.mCurChapter = mBaseBook.mChapters.get(mBaseBook.mReaderingInfo.mIndex);
			mBaseBook.mReaderingInfo.mMarkPos = mBaseBook.mReaderingInfo.mCurChapter.mPosBegin;
		}
		mBufEnd = (int)mBaseBook.mReaderingInfo.mMarkPos;
		StringBuffer text = new StringBuffer();
		mLines.clear();
		mLines = getPageNextText(mBaseBook.mReaderingInfo.mCurChapter.mPosEnd);
		for(int i=0;i<mLines.size();i++){
			text.append(mLines.get(i)+"\n");
		}
		Log.d("nextPage", "text:"+text);
		return text.toString();
	}

	@Override
	public String nextPage() {
		// TODO Auto-generated method stub
		
		if(mBufEnd >= mBaseBook.mReaderingInfo.mCurChapter.mPosEnd && 
				mBaseBook.mReaderingInfo.mIndex+1<mBaseBook.mChapters.size()){
			mBaseBook.mReaderingInfo.mIndex++;
			mBaseBook.mReaderingInfo.mCurChapter = mBaseBook.mChapters.get(mBaseBook.mReaderingInfo.mIndex);
			mBaseBook.mReaderingInfo.mMarkPos = mBaseBook.mReaderingInfo.mCurChapter.mPosBegin;
			mBufEnd = (int)mBaseBook.mReaderingInfo.mCurChapter.mPosBegin;
		}
		StringBuffer text = new StringBuffer();
		mLines.clear();
		mLines = getPageNextText(mBaseBook.mReaderingInfo.mCurChapter.mPosEnd);
		for(int i=0;i<mLines.size();i++){
			text.append(mLines.get(i)+"\n");
			Log.d("nextPage"+i, "text:"+mLines.get(i));
		}
		
		return text.toString();
	}

	@Override
	public String previousChapter() {
		// TODO Auto-generated method stub
		if(mBaseBook.mReaderingInfo.mIndex-1>=0){
			mBaseBook.mReaderingInfo.mIndex--;
			mBaseBook.mReaderingInfo.mCurChapter = mBaseBook.mChapters.get(mBaseBook.mReaderingInfo.mIndex);
			mBaseBook.mReaderingInfo.mMarkPos = mBaseBook.mReaderingInfo.mCurChapter.mPosBegin;
		}
		mBufEnd = (int)mBaseBook.mReaderingInfo.mMarkPos;
		StringBuffer text = new StringBuffer();
		mLines.clear();
		mLines = getPageNextText(mBaseBook.mReaderingInfo.mCurChapter.mPosEnd);
		for(int i=0;i<mLines.size();i++){
			text.append(mLines.get(i)+"\n");
		}
		Log.d("nextPage", "text:"+text);
		return text.toString();
	}

	@Override
	public String previousPage() {
		if(mBufBegin <= mBaseBook.mReaderingInfo.mCurChapter.mPosBegin 
				&& mBaseBook.mReaderingInfo.mIndex-1>=0){
				mBaseBook.mReaderingInfo.mIndex--;
				mBaseBook.mReaderingInfo.mCurChapter = mBaseBook.mChapters.get(mBaseBook.mReaderingInfo.mIndex);
				mBaseBook.mReaderingInfo.mMarkPos = mBaseBook.mReaderingInfo.mCurChapter.mPosEnd;
				mBufBegin = (int)mBaseBook.mReaderingInfo.mMarkPos;
			}
			
			StringBuffer text = new StringBuffer();
			mLines.clear();
			mLines = getPagePrevious();
			for(int i=0;i<mLines.size();i++){
				text.append(mLines.get(i)+"\n");
				Log.d("previousPage "+i,mLines.get(i));
			}
			return text.toString();
	}

	@Override
	public String refreshPage() {
		mBaseBook.mReaderingInfo.mCurChapter = mBaseBook.mChapters.get(mBaseBook.mReaderingInfo.mIndex);
		mBufEnd = (int) mBaseBook.mReaderingInfo.mMarkPos;
		StringBuffer text = new StringBuffer();
		mLines.clear();
		mLines = getPageNextText(mBaseBook.mReaderingInfo.mCurChapter.mPosEnd);
		for(int i=0;i<mLines.size();i++){
			text.append(mLines.get(i)+"\n");
			Log.d("nextPage"+i, "text:"+mLines.get(i));
		}
		
		return text.toString();
	}
	
	/**
	 * 获取下一页数据
	 * @param endPos
	 * @return
	 */
	private Vector<String> getPageNextText(long endPos){
		mBaseBook.mReaderingInfo.mMarkPos = mBufEnd;
		mBufBegin = mBufEnd;
		String strParagraph = "";
		Vector<String> lines = new Vector<String>();
		while(lines.size() <= 0){
			while(lines.size() < mReaderFormate.mLineCount && mBufEnd < endPos){
				strParagraph = readParagraphNext(mBufEnd);
				String strReturn = "";
				if (strParagraph.indexOf("\r\n") != -1) {
					strReturn = "\r\n";
					strParagraph = strParagraph.replaceAll("\r\n", "");
				} else if (strParagraph.indexOf("\n\n") != -1) {
					strReturn = "\n\n";
					strParagraph = strParagraph.replaceAll("\n\n", "");
				}else if (strParagraph.indexOf("\n") != -1) {
					strReturn = "\n";
					strParagraph = strParagraph.replaceAll("\n", "");
				}

				if (strParagraph.length() == 0) {
					lines.add(strParagraph);
				}
				mBufEnd = mBufEnd + strParagraph.length()+strReturn.length();
				while (strParagraph.length() > 0) {
					int nSize = mReaderFormate.mPaint.breakText(strParagraph, true, mReaderFormate.mPageW,
							null);
					lines.add(strParagraph.substring(0, nSize));
					strParagraph = strParagraph.substring(nSize);
					if (lines.size() >= mReaderFormate.mLineCount) {
						break;
					}
				}
				
				if (strParagraph.length() != 0) {
						mBufEnd -= (strParagraph+ strReturn)
								.length();
				}
			}
		}
		return lines;
	}
	
	private String readParagraphNext(int nFromPos){
		String text = mBaseBook.mReaderingInfo.mCurChapter.mContent.substring(nFromPos+1);
		int end = text.length();
		if(text.indexOf("\r")!= -1){
			end = text.indexOf("\r");
		}else if(text.indexOf("\n\n")!= -1){
			end = text.indexOf("\n\n");
		}else if(text.indexOf("\n")!= -1){
			end = text.indexOf("\n");
		}else if(text.indexOf("\r\n")!= -1){
			end = text.indexOf("\r\n");
		}
		
		return mBaseBook.mReaderingInfo.mCurChapter.mContent.substring(nFromPos, nFromPos+1+end);
	}

	private Vector<String> getPagePrevious(){
		if(mBufBegin <= mBaseBook.mChapters.get(0).mPosBegin)
			mBufBegin = (int)mBaseBook.mChapters.get(0).mPosBegin;
		mBufEnd = mBufBegin;
		Vector<String> lines = new Vector<String>();
		String strParagraph = "";
		while(lines.size() <=0){
			while(lines.size() < mReaderFormate.mLineCount && mBufBegin>=0){
				Vector<String> paraLines = new Vector<String>();
				strParagraph= readParagraphPrevious(mBufBegin);
				mBufBegin -= strParagraph.length();
				
				strParagraph = strParagraph.replaceAll("\r\n", "");
				strParagraph = strParagraph.replaceAll("\n", "");
				if (strParagraph.length() == 0) {
					paraLines.add(strParagraph);
				}
				while (strParagraph.length() > 0) {
					int nSize = mReaderFormate.mPaint.breakText(strParagraph, true, mReaderFormate.mPageW,
							null);
					paraLines.add(strParagraph.substring(0, nSize));
					strParagraph = strParagraph.substring(nSize);
				}
				lines.addAll(0, paraLines);
			}
			while (lines.size() > mReaderFormate.mLineCount) {
					mBufBegin += lines.get(0).length();
					lines.remove(0);
			}
		}
		mBaseBook.mReaderingInfo.mMarkPos = mBufBegin;
		return lines;
	}
	
	/**
	 * 读取上一段落
	 * @param nFromPos
	 * @return
	 */
	private String readParagraphPrevious(int nFromPos){
		String text = mBaseBook.mReaderingInfo.mCurChapter.mContent.substring(0,nFromPos);
		int end = 0;
		if(text.lastIndexOf("\r")!= -1){
			end = text.lastIndexOf("\r");
		}else if(text.lastIndexOf("\n\n")!= -1){
			end = text.lastIndexOf("\n\n");
		}else if(text.lastIndexOf("\n")!= -1){
			end = text.lastIndexOf("\n");
		}else if(text.lastIndexOf("\r\n")!= -1){
			end = text.lastIndexOf("\r\n");
		}
		
		return mBaseBook.mReaderingInfo.mCurChapter.mContent.substring(end, nFromPos);
	}
}
